package org.guegan.util.dircompare.swt;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.ProgressBar;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.swt.widgets.Widget;
import org.guegan.util.dircompare.bean.DirBean;
import org.guegan.util.dircompare.main.EstimationDirScanner;
import org.guegan.util.dircompare.main.MainModule;
import org.guegan.util.dircompare.main.ProgressionCallbackListener;
import org.guegan.util.dircompare.main.TreeLoader;
import org.guegan.util.dircompare.util.Factory;

public class SwtMain implements ProgressionCallbackListener {
	private static Log log = LogFactory.getLog(SwtMain.class);
	
	private List<Widget> toDispose = new ArrayList<Widget>();
	private ProgressBar pb;
	private Text text;
	private Tree tree;
	
	/**
	 * Invokes as a standalone program.
	 */
	public static void main(String[] args) {
		Display display = new Display();
		Shell shell = new Shell(display, SWT.SHELL_TRIM);
		shell.setLayout(new FillLayout(SWT.VERTICAL));
		SwtMain instance = new SwtMain(shell);
		
		shell.setText("MachinTruc");
		setShellSize(instance, shell);
		shell.open();
		while (! shell.isDisposed()) {
			if (! display.readAndDispatch()) display.sleep();
		}
		instance.dispose();
		display.dispose();
	}

	static void setShellSize(SwtMain instance, Shell shell) {
		Point size = shell.computeSize(SWT.DEFAULT, SWT.DEFAULT);
		Rectangle monitorArea = shell.getMonitor().getClientArea();
		shell.setSize(Math.min(size.x, monitorArea.width), Math.min(size.y, monitorArea.height));
	}
	
	public SwtMain(Composite parent) {
		Group group = new Group(parent, SWT.SHADOW_OUT);
		group.setLayout(new FillLayout());
		toDispose.add(group);
		addButton("CleanPresenceFlag", group);
		addButton("ROScanner", group);
		addDirScannerButton(group);
		addButton("DeletedFinder", group);
		addButton("DeletedRemover", group);
		addButton("DuplFinder", group);
		addButton("MonoFinder", group);
		addButton("SameNameFinder", group);
		addLoadTreeButton(group);

		Group horiz = newGroup(parent, SWT.HORIZONTAL);
		Group vert = newGroup(horiz, SWT.VERTICAL);
		
		pb = new ProgressBar(vert, SWT.LEFT_TO_RIGHT);
		toDispose.add(pb);
		
		Group group2 = newGroup(vert, SWT.HORIZONTAL);
		text = new Text(group2, SWT.MULTI|SWT.H_SCROLL|SWT.V_SCROLL);
		toDispose.add(text);
		
		tree = initTree(horiz);
	}
	
	private Group newGroup(Composite parent, int style) {
		Group ret = new Group(parent, SWT.NONE);
		ret.setLayout(new FillLayout(style));
		toDispose.add(ret);
		return ret;
	}
	
	private Tree initTree(Group group) {
		Tree ret = new Tree(group, SWT.MULTI);
		ret.setHeaderVisible(true);
		toDispose.add(ret);
		TreeColumn col = new TreeColumn(ret, SWT.NONE);
		col.setText("name");
		col.setWidth(500);
		toDispose.add(col);
		col = new TreeColumn(ret, SWT.NONE);
		col.setText("nb files");
		toDispose.add(col);
		col = new TreeColumn(ret, SWT.NONE);
		col.setText("present");
		toDispose.add(col);
		int columnCount = ret.getColumnCount();
		for (int i = 0; i < columnCount; i++) {
			TreeColumn treeColumn = ret.getColumn(i);
			treeColumn.pack();
		}
		return ret;
	}
	
	private void addButton(String name, Composite parent) {
		Button but = new Button(parent, SWT.PUSH);
		  but.setText(name);
		  but.addListener(SWT.MouseDown, new ButtonActionListener(name, this, text));
		  toDispose.add(but);
	}
	
	private void displayText(String output) {
		if (!text.isDisposed()) {
			final String out = (output != null) ? output : "";
			Display display = text.getDisplay();
			display.asyncExec(new Runnable() {
				@Override
				public void run() {
					text.setText(out);
				}
			});
		}
	}
	
	private void addDirScannerButton(final Composite parent) {
		Button but = new Button(parent, SWT.PUSH);
		  but.setText("DirScanner");
		  but.addListener(SWT.MouseDown, new Listener() {
			
			@Override
			public void handleEvent(Event event) {
				EstimationDirScanner un = Factory.getBean("ROScanner");
				un.execute();
				int total = un.getToScan();
				if (total > 0 || un.getDirsToScan() > 0) {
					pb.setMaximum(total);
					final MainModule module = Factory.getBean("DirScanner");
					module.setListener(new ScanActionListener(parent, pb));
					new Thread() {
						public void run() {
							module.execute();
							displayText(module.getTextOutput());
						}
					}.start();
				}
				else {
					log.info("No file/dir to modify");
				}
			}
		  });
		  toDispose.add(but);
	}
	
	private void addLoadTreeButton(final Composite parent) {
		Button but = new Button(parent, SWT.PUSH);
		  but.setText("Load Tree");
		  but.addListener(SWT.MouseDown, new Listener() {
			
			@Override
			public void handleEvent(Event event) {
				
				final TreeLoader module = Factory.getBean("TreeLoader");
				//module.setListener(new ScanActionListener(parent, pb));
				new Thread() {
					public void run() {
						module.execute();
						Display display = parent.getDisplay();
						display.asyncExec(new Runnable() {
							public void run() {
								buildTree(module);
							}
						});
					}
				}.start();
			}
		  });
		  toDispose.add(but);
	}

	@SuppressWarnings("unchecked")
	protected void buildTree(TreeLoader module) {
		List<DirBean> roots = (List<DirBean>) module.getResult();
		if (roots != null) {
			tree.clearAll(true);
			for (DirBean dir : roots) {
				TreeItem item = new TreeItem(tree, SWT.NONE);
				buildBranch(dir, item);
			}
		}
		else {
		}
	}
	
	private void buildBranch(DirBean dir, TreeItem item) {
		Set<DirBean> subdirs = dir.getSubdirs();
		String name = dir.getName();;
		while (subdirs != null && subdirs.size() == 1 && dir.getNbFiles() == 0) {
			dir = subdirs.iterator().next();
			subdirs = dir.getSubdirs();
			name += "/" + dir.getName();
		}
		item.setText(name);
		item.setText(1, "" + dir.getNbFiles());
		item.setText(2, "" + dir.isPresent());
		if (subdirs != null) {
			for (DirBean sub : subdirs) {
				TreeItem subItem = new TreeItem(item, SWT.NONE);
				buildBranch(sub, subItem);
			}
		}
	}
	/**
	 * Disposes of all resources associated with a particular
	 * instance of the ControlExample.
	 */	
	public void dispose() {
		for (Widget w : toDispose) {
			w.dispose();
		}
	}
	

	@Override
	public boolean progressionCallback(boolean isScanned) {
		return false;
	}
}
